package pers.ree.demo.concurrent;

import org.junit.Test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class BlockingQueueDemo {

    public static void main(String[] args) {
        BlockingQueue blockingQueue = new ArrayBlockingQueue(2);
        for (int i=0; i<2; i++) {
            // add方法底层也是调用offer，offer成功return true，否则抛异常
            blockingQueue.add(i+1);
        }

        System.out.println("begin size=" + blockingQueue.size());


        /** add, element, remove，添加或返回(移出)元素，会抛出异常 */
        // 添加元素，队列已满，直接抛出异常，IllegalStateException: Queue full
//        blockingQueue.add(3);

        // 返回队列头元素，但是队列元素不会减少
        // 底层调的是peek，队列为空时，peek返回null，element抛异常
        int topElement = (int) blockingQueue.element();
        System.out.println("after element(), size=" + blockingQueue.size() + ", topElement=" + topElement);

        // clear底层循环调poll
//        blockingQueue.clear();
//        System.out.println("after clear(), size=" + blockingQueue.size());
        // 队列为空时，抛出异常NoSuchElementException
//        blockingQueue.element();

//        blockingQueue.clear();
//        // 移出并返回头元素，底层调用poll，队列为空时，抛异常NoSuchElementException
//        topElement = (int) blockingQueue.remove();


        /** offer, poll，remove(Object o)，返回值为boolean，不会阻塞或抛异常 */
        // 添加元素，如果队列已满，返回false，不会阻塞或者抛异常
        boolean offerResult = blockingQueue.offer(3);
        // offerResult=false
        System.out.println("offerResult=" + offerResult);

        // 移除指定元素，返回值为boolean
        boolean removeResult = blockingQueue.remove(3);
        // removeResult=false
        System.out.println("result=" + removeResult);


         /** put, take，添加或移出元素，会阻塞 */
//        try {
//            // 添加元素，如果队列已满则阻塞
//            // 底层是调用Condition的await方法进行阻塞
//            blockingQueue.put(3);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

//        blockingQueue.clear();
//        try {
//            // 移出并返回头元素，如果队列为空则阻塞
//            // 底层调Conditon的await方法进行阻塞
//            topElement = (int) blockingQueue.take();
//            System.out.println("after take(), size=" + blockingQueue.size() + ", topElement=" + topElement);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }


        /** peek, poll，返回头元素，不存在时返回null */
        // peek返回队列头元素（元素不会移出队列），如果不存在返回null
        topElement = (int) blockingQueue.peek();
        System.out.println("after peek topElement, size=" + blockingQueue.size() + ", topElement=" + topElement);
//        blockingQueue.clear();
//        // 队列为空，peek返回null
//        Integer nullElement = (Integer) blockingQueue.peek();
//        System.out.println("after peek nullElement, size=" + blockingQueue.size() + ", nullElement=" + nullElement);

        // poll移出并返回头元素，队列为空，返回null
        topElement = (int) blockingQueue.poll();
        System.out.println("after poll topElement, size=" + blockingQueue.size() + ", topElement=" + topElement);
        int endElement = (int) blockingQueue.poll();
        System.out.println("after poll endElement, size=" + blockingQueue.size() + ", endElement=" + endElement);
        // 队列为空，poll返回null
        Integer nullElement = (Integer) blockingQueue.poll();
        System.out.println("after poll nullElement, size=" + blockingQueue.size() + ", nullElement=" + nullElement);



        // BlockingQueue不接受null元素，add,offer,put添加null，会抛出空指针异常
//        blockingQueue.add(null);
//        blockingQueue.offer(null);
//        try {
//            blockingQueue.put(null);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }


        System.out.println("end, size=" + blockingQueue.size());
    }

    @Test
    public void removeTest() {
        BlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(2);
        boolean result = arrayBlockingQueue.remove(1);
        System.out.println(result);


        BlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(2);
        result = linkedBlockingQueue.remove(2);
//        linkedBlockingQueue.remove();
        System.out.println(result);
    }

    @Test
    public void putAndTakeTest() {
        BlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(2);
        try {
            arrayBlockingQueue.put(1);
            // 阻塞
            Integer i = arrayBlockingQueue.take();
            System.out.println(i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
